﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharpMUD.Framework.Services;
using SharpMUD.Framework.ComponentModel;

namespace SharpMUD.Application
{
    public partial class MudServerApplication
        : IServicesHost
    {
        private List<IService> _LoadedServices = new List<IService>();

        protected void AddService(BootStrap.ServiceConfigurationEntryBase serviceConfigurationEntry,bool initialize)
        {
            if (serviceConfigurationEntry == null)
                throw new ArgumentNullException("serviceConfigurationEntry");
            log.Info("Adding Service {" + serviceConfigurationEntry.ServiceTypeType.FullName + "}");
            if (this._LoadedServices.Where((s) => s.GetType() == serviceConfigurationEntry.ServiceTypeType).Count() > 0)
            {
                throw new InvalidOperationException("Cannot add the service because a service of the same type is already present");
            }
            var serviceInstance = serviceConfigurationEntry.CreateServiceInstance();
            _LoadedServices.Add(serviceInstance);
            if (this.ServiceAdded != null)
                this.ServiceAdded(this, new ServiceAddRemoveEventArgs(serviceConfigurationEntry.ServiceTypeType));
            if(initialize)
                serviceInstance.Initialize(this);
            log.Info("Service Added {" + serviceConfigurationEntry.ServiceTypeType.FullName + "}");
            if(this.ServiceAdded!=null)
                this.ServiceAdded(this, new ServiceAddRemoveEventArgs(serviceInstance.GetType()));
        }

        private void AddService(IService serviceInstance, bool initialize)
        {
            if (serviceInstance == null)
                throw new ArgumentNullException("serviceInstance");

            log.Info("Adding Service Instance {" + serviceInstance.GetType().AssemblyQualifiedName + "}");
            if (this._LoadedServices.Where((s) => s.GetType() == serviceInstance.GetType()).Count() > 0)
            {
                throw new InvalidOperationException("Cannot add the service because a service of the same type is already present");
            }
            _LoadedServices.Add(serviceInstance);
            if (this.ServiceAdded != null)
                this.ServiceAdded(this, new ServiceAddRemoveEventArgs(serviceInstance.GetType()));
            if(initialize)
                serviceInstance.Initialize(this);
            log.Info("Service Instance Added {" + serviceInstance.GetType().AssemblyQualifiedName + "}");
            if(this.ServiceAdded!=null)
                this.ServiceAdded(this, new ServiceAddRemoveEventArgs(serviceInstance.GetType()));
        }

        #region IServicesHost Members

        public IService GetService(Type serviceType)
        {
            var result = _LoadedServices.First(s => (s.GetType().Equals(serviceType)));
            if(result==null)
            {
                result = _LoadedServices.First( s=>serviceType.IsAssignableFrom(s.GetType()));
            }
            return result;
        }

        public T GetService<T>() where T : IService
        {
            var result = _LoadedServices.FirstOrDefault(s => (s.GetType().Equals(typeof(T))));
            if(result==null)
            {
                result = _LoadedServices.First( s=>typeof(T).IsAssignableFrom(s.GetType()));
            }
            if(result == null)
                return default(T);
            else
                return (T)result;
        }

        public event EventHandler<ServiceAddRemoveEventArgs> ServiceAdded;

        public event EventHandler<ServiceAddRemoveEventArgs> ServiceRemoved;

        #endregion

        #region IServiceProvider Members

        object IServiceProvider.GetService(Type serviceType)
        {
            return GetService(serviceType);
        }

        #endregion

        #region IEnumerable<IService> Members

        public IEnumerator<IService> GetEnumerator()
        {
            return _LoadedServices.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        public IEnumerable<IService> Services
        {
            get
            {
                lock (this._LoadedServices)
                {
                    return _LoadedServices;
                }
            }
        }

        #endregion
    }
}
